package com.data.modules.system.service.impl;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.XmlUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.data.common.exception.BootException;
import com.data.common.system.vo.LoginUser;
import com.data.common.util.RestUtil;
import com.data.config.thirdapp.ThirdAppConfig;
import com.data.config.thirdapp.ThirdAppTypeItemVo;
import com.data.config.thirdapp.ThirdAppURLConfig;
import com.data.modules.feign.AdminService;
import com.data.modules.system.entity.SysThirdAccount;
import com.data.modules.system.entity.SysUser;
import com.data.modules.system.model.CommitApprovalApplyParam;
import com.data.modules.system.model.CommitDingTalkApplyParam;
import com.data.modules.system.model.WeixinConfigDTO;
import com.data.modules.system.service.IOaService;
import com.data.modules.system.service.ISysThirdAccountService;
import com.data.modules.system.service.ISysUserService;
import com.data.modules.system.util.crypto.DingCallbackCrypto;
import com.data.modules.system.util.crypto.WxCpCryptUtil;
import com.data.modules.system.util.crypto.WxCryptUtil;
import com.jeecg.qywx.api.core.util.HttpUtil;
import com.jeecg.qywx.api.user.JwUserAPI;
import com.jeecg.qywx.api.user.vo.User;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.core.io.FileUrlResource;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.ObjectUtils;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

import javax.servlet.http.HttpServletRequest;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 类的描述
 *
 * @author: cg
 * @since: 2022-02-10 14:20
 **/
@Slf4j
@Service
@SuppressWarnings("ALL")
public class OaServiceImpl implements IOaService {

    @Autowired
    ThirdAppConfig thirdAppConfig;
    @Autowired
    ThirdAppWechatEnterpriseServiceImpl thirdAppWechatEnterpriseService;
    @Autowired
    ThirdAppFeiShutalkServiceImpl thirdAppFeiShutalkService;
    @Autowired
    @Lazy
    AdminService adminService;
    @Autowired
    ThirdAppDingtalkServiceImpl thirdAppDingtalkService;
    @Autowired
    ISysThirdAccountService sysThirdAccountService;
    @Autowired
    ISysUserService sysUserService;

    private WxCpCryptUtil getWXBizMsgCrypt() {
        WxCpCryptUtil cryptUtil = new WxCpCryptUtil(this.thirdAppConfig.getWechatEnterprise());
        return cryptUtil;
    }


    private String getContentByTagName(Element root, String tagName){
        NodeList nodelist = root.getElementsByTagName(tagName);
        String Content = nodelist.item(0).getTextContent();
        return Content;
    }


    private void dealWeiChatTextMsg(Element root) {
        String content = getContentByTagName(root,"Content");
        System.out.println("Content：" + content);

        content = getContentByTagName(root,"FromUserName");
        System.out.println("FromUserName：" + content);
    }

    private void dealWeiChatEventMsg(Element root) {
        String event = getContentByTagName(root,"Event");

        //OA审批流
        if (StringUtils.equals("sys_approval_change",event)){
            String spName = getContentByTagName(root,"SpName");
            log.info("审批模板名称：{}" , spName);

            //SpStatus	申请单状态：1-审批中；2-已通过；3-已驳回；4-已撤销；6-通过后撤销；7-已删除；10-已支付
            String spStatus = getContentByTagName(root,"SpStatus");
            log.info("====spStatus===>{}",spStatus);
            //审批申请状态变化类型：1-提单；2-同意；3-驳回；4-转审；5-催办；6-撤销；8-通过后撤销；10-添加备注
            String statuChangeEvent = getContentByTagName(root,"StatuChangeEvent");
            //审批编号
            String spNo = getContentByTagName(root,"SpNo");

            //离职审批事件 部门领导人通过修改离职时间 多次提交审批覆盖  领导人通过后驳回不考虑 cmg
            if (StringUtils.equals("离职", spName) && StringUtils.equals("2", spStatus) && StringUtils.equals("2", statuChangeEvent)) {
                //提交人
                String userId = getContentByTagName(root,"UserId");
                quitExtracted(spNo, userId);
            } else if (StringUtils.equals("合同审批", spName)) {
                contractExtracted(spNo,root);
            }

        }
    }


    private void contractExtracted(String spNo, Element root) {
        JSONObject jsonObjectXml = XmlUtil.xmlToBean(root, JSONObject.class);
        log.info("====jsonObjectXml===>{}",jsonObjectXml.toJSONString());

        //审批流程信息，可能有多个审批节点。
        JSONObject approvalInfo = jsonObjectXml.getJSONObject("ApprovalInfo");
        Integer spStatus = approvalInfo.getInteger("SpStatus");
        log.info("====spStatus===>{}",spStatus);
        Integer StatuChangeEvent = approvalInfo.getInteger("StatuChangeEvent");
        log.info("====StatuChangeEvent===>{}",StatuChangeEvent);

        //审批申请状态变化类型：1-提单；2-同意；3-驳回；4-转审；5-催办；6-撤销；8-通过后撤销；10-添加备注
        Integer statuChangeEvent = approvalInfo.getInteger("StatuChangeEvent");

        Object spRecordObj = approvalInfo.get("SpRecord");
        log.info("spRecordObj===>{}",JSON.toJSONString(spRecordObj));

        StringBuffer buffer = new StringBuffer();

        if (spRecordObj instanceof Map) {
            JSONObject spRecord = approvalInfo.getJSONObject("SpRecord");
            buffer.append(this.detailsExtracted(spRecord));
        }else {
            JSONArray spRecordObjs = approvalInfo.getJSONArray("SpRecord");
            for (Object recordObj : spRecordObjs) {
                JSONObject spRecord=(JSONObject) JSONObject.toJSON(recordObj);

                if (buffer.length() > 0){
                    buffer.append("-->" + this.detailsExtracted(spRecord));
                }else {
                    buffer.append(this.detailsExtracted(spRecord));
                }
            }
        }

        //更新合同状态  审批申请状态变化类型：1-提单；2-同意；3-驳回；4-转审；5-催办；6-撤销；8-通过后撤销；10-添加备注
        //hlContractService.changeSpStatus(spNo,buffer.toString(),spStatus);


//        //合同变更接受通知
//        String appAccessToken = thirdAppWechatEnterpriseService.getAppAccessToken();
//        log.info("====appAccessToken====>{}",appAccessToken);
//        if (appAccessToken == null) {
//            log.error("appAccessToken获取失败！");
//        }
//        //获取审批申请详情
//        JSONObject jsonObject = getapprovaldetail(spNo, appAccessToken);
//        if (ObjectUtils.isEmpty(jsonObject) || jsonObject.getInteger("errcode") != 0) {
//            log.info("获取合同审批申请详情为空或错误{}",jsonObject);
//            return;
//        }
//        log.info("====获取合同审批申请详情====>{}",jsonObject);
    }

    private String detailsExtracted(JSONObject spRecord) {
        //单个审批节点信息描述
        StringBuffer buffer = new StringBuffer();

        //审批节点状态：1-审批中；2-已同意；3-已驳回；4-已转审
        Integer spStatus = spRecord.getInteger("SpStatus");
        //节点审批方式：1-或签；2-会签
        Integer approverAttr = spRecord.getInteger("ApproverAttr");

//        buffer.append(approverAttrStr(approverAttr));
        buffer.append(spSatusStr(spStatus));

        //单个审批节点详情。当节点为标签或上级时，一个节点可能有多个分支
        Object detailsObj = spRecord.get("Details");
        if (detailsObj instanceof Map) {
            JSONObject details = spRecord.getJSONObject("Details");

            Integer status = details.getInteger("SpStatus");
            String speech = details.getString("Speech");
            JSONObject approver = details.getJSONObject("Approver");
            //节点分支审批人审批操作时间，0为尚未操作
            Long spTime = details.getLong("SpTime");

            this.approverOne(buffer, spTime, speech, approver);
        }else {
            //多个 审批节点详情。当节点为标签或上级时，一个节点可能有多个分支
            JSONArray detailss = spRecord.getJSONArray("Details");
            for (int i = 0; i < detailss.size(); i++) {
                JSONObject detail= (JSONObject) JSONObject.toJSON(detailss.get(i));
                Integer status = detail.getInteger("SpStatus");
                String speech = detail.getString("Speech");

                JSONObject approver = detail.getJSONObject("Approver");
                String userId = approver.getString("UserId");
                //节点分支审批人审批操作时间，0为尚未操作
                Long spTime = detail.getLong("SpTime");
                // Details
                this.approverOne(buffer, spTime, speech, approver);
                if ((detailss.size() - 1)  != i){
                    buffer.append(",");
                }
            }
        }
        return buffer.toString();
    }

    /**
     *
     * @param buffer
     * @param spTime  节点分支审批人审批操作时间，0为尚未操作
     * @param speech  分支审批人审批状态
     * @param approver
     */
    private void approverOne(StringBuffer buffer, Long spTime, String speech, JSONObject approver) {
        String userId = approver.getString("UserId");
        String spTimeStr = "(尚未操作)";
        log.info("spTimeStr===>{}",spTimeStr);
        if (spTime != 0){
            spTimeStr = "("+ DateUtil.formatDateTime(new Date(spTime * 1000))+")";
        }

        String name = userId;
        SysThirdAccount thirdAccount = sysThirdAccountService.getOneByThirdUserId(userId, ThirdAppConfig.WECHAT_ENTERPRISE.toLowerCase());
        if (ObjectUtil.isNotEmpty(thirdAccount)){
            SysUser user = sysUserService.getById(thirdAccount.getSysUserId());
            if (ObjectUtil.isNotEmpty(user) && ObjectUtil.isNotEmpty(user.getRealname())){
                name = user.getRealname();
            }
        }
        buffer.append(name);
//        buffer.append(spTimeStr);
        buffer.append(":");
        buffer.append(ObjectUtils.isEmpty(speech) ? "无" : speech);
    }

    private String approverAttrStr(Integer approverAttr) {
        switch (approverAttr){
            case 1:
                return "[或签]";
            case 2:
                return "[会签]";
            default:
               return "[未知]";
        }
    }

    private String spSatusStr(Integer spStatus) {
        switch (spStatus) {
            case 1:
                return "[审批中]";
            case 2:
                return "[已同意]";
            case 3:
                return "[已驳回]";
            case 4:
                return "[已转审]";

            default:
                return "[未知]";
        }
    }

    @Override
    public WeixinConfigDTO getTweixinConfig(String url) {
        WeixinConfigDTO tWeixinConfig = new WeixinConfigDTO();

        return tWeixinConfig;
    }

    @Override
    public String verifyURL(String msg_signature, String timestamp, String nonce, String echostr) {
        try {
            WxCpCryptUtil wxcpt = getWXBizMsgCrypt();
            //需要返回的明文
            String sEchoStr = wxcpt.verifyURL(msg_signature, timestamp,nonce, echostr);
            return sEchoStr;
        } catch (Exception e) {
            //验证URL失败，错误原因请查看异常
            log.error(e.getMessage(),e);
        }
        return "无";
    }

    @Override
    public void  doCallBack(HttpServletRequest request, String msg_signature, String timestamp, String nonce) {
        // post请求的密文数据
        Element root = null;
        try {
            WxCpCryptUtil wxcpt = getWXBizMsgCrypt();

            InputStream inputStream = request.getInputStream();
            String sPostData = IOUtils.toString(inputStream,"UTF-8");
            String sMsg = wxcpt.decrypt(msg_signature, timestamp, nonce, sPostData);
            System.out.println("after decrypt msg: " + sMsg);
            //  解析出明文xml标签的内容进行处理
            // For example:
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            DocumentBuilder db = dbf.newDocumentBuilder();
            StringReader sr = new StringReader(sMsg);
            InputSource is = new InputSource(sr);
            Document document = db.parse(is);
            root = document.getDocumentElement();

        } catch (Exception e) {
            log.error("解密失败，失败原因请查看异常:{}",e.getMessage());
            e.printStackTrace();
        }

        //获取消息类型
        String msgType = getContentByTagName(root,"MsgType");
        log.info("MsgType：" + msgType);
        //处理文本信息
        if ("Content".equalsIgnoreCase(msgType)){
            dealWeiChatTextMsg(root);
        }else if ("event".equalsIgnoreCase(msgType)){
            //处理事件信息
            dealWeiChatEventMsg(root);
        }
    }

    private void quitExtracted(String spNo, String userId) {
        String appAccessToken = thirdAppWechatEnterpriseService.getAppAccessToken();
        log.info("====appAccessToken====>{}",appAccessToken);
        if (appAccessToken == null) {
            log.error("appAccessToken获取失败！");
        }
        //获取审批申请详情
        JSONObject jsonObject = getapprovaldetail(spNo, appAccessToken);
        log.info("====获取审批申请详情====>{}",jsonObject);
        if (ObjectUtils.isEmpty(jsonObject)) {
            log.info("获取审批申请详情为空");
            return ;
        }
        JSONArray array = jsonObject.getJSONObject("info").getJSONObject("apply_data").getJSONArray("contents");
        List<Object> list = array.stream().filter(x -> ("Date-1574499804294".equals(((JSONObject) x).get("id")))).collect(Collectors.toList());
        if (ObjectUtils.isEmpty(list)) {
            log.error("获取 预计离职日期 为空，返回");
            return ;
        }

        log.info("list==>{},{}",list.size(),JSON.toJSONString(list));
        JSONObject leaveJO  = (JSONObject)list.get(0);
        JSONObject value = leaveJO.getJSONObject("value");
        JSONObject date = value.getJSONObject("date");

        //离职时间
        Long leaveTime = date.getLong("s_timestamp");
        log.info("离职时间Long：{}",leaveTime);
        Date leaveDate = new Date(leaveTime * 1000);
        String leaveDateStr = DateUtil.format(leaveDate, DatePattern.NORM_DATETIME_PATTERN);
        log.info("离职时间：{}", leaveDateStr);

        //获取用户信息
        String accessToken = thirdAppWechatEnterpriseService.getAccessToken();
        log.info("====accessToken====>{}",accessToken);
        if (accessToken == null) {
            log.error("accessToken获取失败！");
        }
        User user = JwUserAPI.getUserByUserid(userId, accessToken);
        log.info("user转json：{}", JSONObject.toJSONString(user));
        //通知系统修改离职时间
        String mobile = user.getMobile();
        adminService.updateDepaTime(mobile, leaveDateStr);
    }

    @Override
    public void startOAWorkflow() throws Exception {
        //提交审批申请
        String creatorUserid = "chengang";
        String templateId = "BsAa7tgju6ssRM9BQVU6G2Mv8fm6F3mZWgPcahQtw";
        ThirdAppTypeItemVo config = new ThirdAppTypeItemVo();
        config.setAesKey("yzikLfVpAeO9T6LaqMoHLltRFKOflEXJRz17veYde6c");
        //合同审批
        config.setClientId("3010040");
        WxCryptUtil wxUtil = new WxCpCryptUtil(config);
        //获取token
//        String token = wxUtil.getAccessToken();
        /*//获取页面模板元素信息
        String templateInfo = wxUtil.getTemplateDetail(templateId);
        log.info(templateInfo);*/

        //组装 发起企业微信流程的 业务参数
        CommitApprovalApplyParam param = new CommitApprovalApplyParam(creatorUserid, templateId);
        //添加审批人
        param.addApprover(2, "chengang");
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        //临时素材上传接口返回的的media_id
        String fileId = "2gMMJGQ1Ci0wrVRYaSlq942gH0M7bmxo-wX19zmcXHqSlpNjmTTp5g1K4XX4pnBKy";
        //审批申请数据
        param.setApplyDataContents(
                param.controlText("item-1494250754014", "合同名称CG"),
                param.controlText("item-1494250798972", "我方负责人CG"),
                param.controlText("item-1494250800464", "单位名称"),
                param.controlDate("item-1494250774238","day",String.valueOf(sdf.parse("2022-02-10").getTime()/1000)),
                param.controlFile("item-1494250827380",fileId)
        );
        //摘要信息
        param.setSummaryInfo("CG摘要信息1", "CG摘要信息2", "CG摘要信息3");
        //抄送人
        param.setNotifyer("chengang");
        param.setNotify_type(2);
        log.info(JSON.toJSONString(param));


        String appAccessToken = thirdAppWechatEnterpriseService.getAppAccessToken();
        log.info("====appAccessToken====>{}",appAccessToken);
        if (appAccessToken == null) {
            log.error("appAccessToken获取失败！");
        }
        //调用 执行 审批流程
        String spNo = wxUtil.commitApprovalApply(appAccessToken,param);
        log.info("===spNo:{}",spNo);

    }


    /**
     * 创建企业微信审批流
     * @throws
     * @return
     */
    @Override
    public String wechatEnterpriseApplyevent(CommitApprovalApplyParam param) throws Exception {

        String appAccessToken = thirdAppWechatEnterpriseService.getAppAccessToken();
        log.info("====appAccessToken====>{}",appAccessToken);
        if (appAccessToken == null) {
            log.error("appAccessToken获取失败！");
            throw new BootException("appAccessToken获取失败");
        }
        WxCryptUtil wxUtil = new WxCpCryptUtil(this.thirdAppConfig.getWechatEnterprise());
        //调用 执行 审批流程
        return wxUtil.commitApprovalApply(appAccessToken,param);
    }


    /**
     * 获取审批申请详情
     * @return
     */
    public JSONObject getapprovaldetail(String spNo, String accessToken){
        String getapprovaldetail = "https://qyapi.weixin.qq.com/cgi-bin/oa/getapprovaldetail?access_token=ACCESS_TOKEN";
        log.info("[GETAPPROVALDETAIL]", "getapprovaldetail param:spNo:{},accessToken:{}", new Object[]{spNo,accessToken});
        // 获取审批申请详情
        String url = getapprovaldetail.replace("ACCESS_TOKEN", accessToken);
        JSONObject object = new JSONObject();
        object.put("sp_no",spNo);
        //获取审批申请详情
        System.out.println(object.toJSONString());
        JSONObject jsonObject = HttpUtil.sendPost(url,object.toJSONString());
        log.info("[GETAPPROVALDETAIL]", "getapprovaldetail response:{}", new Object[]{jsonObject});
        return jsonObject;
    }


    /**
     * 上传临时素材
     * @param accessToken
     * @param type  媒体文件类型，分别有图片（image）、语音（voice）、视频（video），普通文件（file）
     * @return
     */
    @Override
    public String mediaUpload(String type, String fileUrl) throws MalformedURLException {
        String accessToken = thirdAppWechatEnterpriseService.getAccessToken();
        RestTemplate restTemplate = new RestTemplate();
        String getapprovaldetail = "https://qyapi.weixin.qq.com/cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE";
        log.info("[mediaUpload]", "mediaUpload param:type:{},accessToken:{}", new Object[]{type,accessToken});
        String url = getapprovaldetail.replace("ACCESS_TOKEN", accessToken).replace("TYPE",type);
        URI uri = UriComponentsBuilder.fromHttpUrl(url).build().toUri();

        URL uriFile = new URL(fileUrl);
        FileUrlResource fileUrlResource = new FileUrlResource(uriFile);
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.MULTIPART_FORM_DATA);
        ContentDisposition build = ContentDisposition.builder("form-data").filename(fileUrlResource.getFilename()).build();
        headers.setContentDisposition(build);
        MultiValueMap<String, Object> params = new LinkedMultiValueMap<>();
        params.add("media", fileUrlResource);
        HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(params, headers);

        JSONObject jsonObject = restTemplate.postForObject(uri,requestEntity , JSONObject.class);
        if (ObjectUtils.isEmpty(jsonObject) || jsonObject.getInteger("errcode") != 0) {
            throw new BootException("上传临时素材失败"+ jsonObject.toJSONString());
        }
        log.info("[mediaUpload]", "mediaUpload response:{}", new Object[]{jsonObject});
        String mediaId = jsonObject.getString("media_id");
        return mediaId;
    }


    @Override
    public String flyBookEnterpriseApplyevent(JSONObject jsonObjct) throws Exception {
        String approveUrl = "https://www.feishu.cn/approval/openapi/v2/instance/create";
        String accessToken = thirdAppFeiShutalkService.getAccessToken();
        if (accessToken != null) {
            accessToken = "Bearer " + accessToken;
        }
        HttpHeaders headers = new HttpHeaders();
        headers.set("Authorization",accessToken);
        headers.setContentType(MediaType.valueOf(MediaType.APPLICATION_JSON_UTF8_VALUE));
        JSONObject responseStr = RestUtil.request(approveUrl, HttpMethod.POST, headers, null, jsonObjct, JSONObject.class).getBody();
        //JSONObject responseStr = JSON.parseObject("{\"msg\":\"\",\"code\":0,\"data\":{\"instance_code\":\"4E3204B1-61C7-4A1C-BD33-10FC56E0A2C4\"}}");
        String reult = null;
        JSONObject resultJson = JSON.parseObject(String.valueOf(responseStr));

        if (ObjectUtil.isNotEmpty(resultJson.get("code"))&&ObjectUtil.equal(resultJson.get("code"),0)){
            JSONObject response = JSON.parseObject(String.valueOf(resultJson.get("data")));
            return  String.valueOf(response.get("instance_code"));
        }else {
            return reult;
        }

    }

    /**
     * 附件飞书上传返回唯一标识
     * @param type
     * @param fileUrl
     * @return
     * @throws MalformedURLException
     */
    @Override
    public String flyBookUpload(String type, String fileUrl) throws MalformedURLException {
        String accessToken = thirdAppFeiShutalkService.getAccessToken();
        if (accessToken != null) {
            accessToken = "Bearer " + accessToken;
        }
        RestTemplate restTemplate = null;
        URI uri = null;
        HttpEntity<MultiValueMap<String, Object>> requestEntity = null;
        try {
            restTemplate = new RestTemplate();
            String getapprovaldetail = "https://www.feishu.cn/approval/openapi/v2/file/upload";
            uri = UriComponentsBuilder.fromHttpUrl(getapprovaldetail).build().toUri();
            URL uriFile = new URL(fileUrl);
            FileUrlResource fileUrlResource = new FileUrlResource(uriFile);
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.MULTIPART_FORM_DATA);
            ContentDisposition build = ContentDisposition.builder("form-data").filename(fileUrlResource.getFilename()).build();
            headers.setContentDisposition(build);
            headers.set("Authorization",accessToken);
            MultiValueMap<String, Object> params = new LinkedMultiValueMap<>();
            params.add("content", fileUrlResource);
            params.add("name", fileUrl);
            params.add("type", type);
            requestEntity = new HttpEntity<>(params, headers);
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
        JSONObject jsonObject = restTemplate.postForObject(uri, requestEntity, JSONObject.class);
        if (org.apache.commons.lang3.ObjectUtils.isEmpty(jsonObject) || jsonObject.getInteger("code") != 0) {
            throw new BootException("上传临时素材失败" + jsonObject.toJSONString());
        }
        log.info("[mediaUpload]", "mediaUpload response:{}", new Object[]{jsonObject});
        JSONObject jsonObjectData = (JSONObject) JSONObject.toJSON(jsonObject.get("data"));
        return String.valueOf(jsonObjectData.get("code"));
    }

    /**
     * 发起钉钉审批
     * @param param
     * @return
     * @throws Exception
     */
    @Override
    public String dingTalkEnterpriseApplyevent(CommitDingTalkApplyParam param) throws Exception {
        String accessToken = thirdAppDingtalkService.getAccessToken();
        log.info("========appAccessToken====>{}",accessToken);
        if (accessToken == null) {
            log.error("accessToken获取失败！");
            throw new BootException("accessToken获取失败");
        }
        String url = ThirdAppURLConfig.URL_SHENPI_CREATE.replace("ACCESS_TOKEN", accessToken);
        log.info("==========请求钉钉审批流url=======>",url);
        //钉钉发起审批
        RestTemplate restTemplate = new RestTemplate();
        ResponseEntity<JSONObject> responseEntity = restTemplate.postForEntity(url, param, JSONObject.class);
        if(responseEntity.getStatusCode() == HttpStatus.OK){
            log.info("========调用钉钉审批流响应参数=========>{}",responseEntity.getBody().toString());
            return responseEntity.getBody().getString("process_instance_id");
        }else {
            log.error("==========调用钉钉审批流错误信息=========>{}",responseEntity.getBody().toJSONString());
            throw new BootException("提交审批流失败");
        }
    }
    /**
     * 钉钉 上传附件 获取space_id
     * @return space_id
     */
    @Override
    public Integer dingTalkUpload() {
        // 获取登录用户信息
        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        String id = sysUser.getId();
        SysThirdAccount thirdAccount = sysThirdAccountService.getOneBySysUserId(id, ThirdAppConfig.DINGTALK.toLowerCase());
        if (ObjectUtil.isEmpty(thirdAccount) || ObjectUtil.isEmpty(thirdAccount.getThirdUserId())) {
            throw new BootException("不是钉钉员工不能提交,如果未同步钉钉用户请先同步");
        }
        //获取钉钉access_token
        String accessToken = thirdAppDingtalkService.getAccessToken();
        //将access_token 拼接url
        String url = ThirdAppURLConfig.URL_SPACE_ID.replace("ACCESS_TOKEN", accessToken);
        //封装请求的 请求体参数
        JSONObject json = new JSONObject();
        json.put("user_id", thirdAccount.getThirdUserId());
        json.put("agent_id", thirdAppConfig.getDingtalk().getAgentId());
        //通过httputil发送请求
        log.info("==========请求钉钉url=========>{}====access_token===>{}=====请求体参数====>{}",url,accessToken,json.toJSONString());
        ResponseEntity<JSONObject> request = RestUtil.request(url, HttpMethod.POST, null, json);
        log.info("=======响应体=======>",request.toString());
        if(request.getBody().getInteger("errcode") != 0){
            throw new BootException("请求钉钉获取space_id失败");
        }
        Integer spaceId = request.getBody().getJSONObject("result").getInteger("space_id");
        return spaceId;

    }

    /**
     * 钉钉  单步文件上传   返回 media_id
     * @param fileUrl 文件url
     * @return
     */
    @Override
    public Map<String,String> dingTalkMediaUpload(String fileUrl) throws IOException {
        String accessToken = thirdAppDingtalkService.getAccessToken();

        RestTemplate restTemplate = new RestTemplate();

        URL uriFile = new URL(fileUrl);

        FileUrlResource fileUrlResource = new FileUrlResource(uriFile);
        long fileSize = fileUrlResource.contentLength();
        log.info("===========文件大小=========>{}",fileSize);

        log.info("[mediaUpload]", "mediaUpload param:type:{},accessToken:{}", new Object[]{accessToken});
        //将need param file_size and agent_Id   两个参数拼接到url上
        String url = ThirdAppURLConfig.URL_SINGLE_UPLOAD.replace("ACCESS_TOKEN",accessToken);
        String s = url + "&file_size="+fileSize+"&agent_id=" + thirdAppConfig.getDingtalk().getAgentId();
        log.info("=====请求钉钉url===========>{}",s);
        URI uri = UriComponentsBuilder.fromHttpUrl(s).build().toUri();

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.MULTIPART_FORM_DATA);
        ContentDisposition build = ContentDisposition.builder("form-data").filename(fileUrlResource.getFilename()).build();
        headers.setContentDisposition(build);
        MultiValueMap<String, Object> params = new LinkedMultiValueMap<>();
        params.add("media", fileUrlResource);

        HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(params, headers);

        JSONObject jsonObject = restTemplate.postForObject(uri,requestEntity , JSONObject.class);
        if (ObjectUtils.isEmpty(jsonObject) || jsonObject.getInteger("errcode") != 0) {
            throw new BootException("上传临时素材失败"+ jsonObject.toJSONString());
        }
        log.info("[mediaUpload]", "mediaUpload response:{}", new Object[]{jsonObject});
        String mediaId = jsonObject.getString("media_id");
        //todo 需要通过media_id 去获得fileId
//获取spaceId
        Integer spaceId = this.dingTalkUpload();
        String url2 = ThirdAppURLConfig.URL_ADD_FILE.replace("ACCESS_TOKEN",accessToken);


        String s2 = url2 + "&agent_id="+thirdAppConfig.getDingtalk().getAgentId()+"&code=" + "f99e755873ed39d788475f6e06de2cbc"+"&media_id="+mediaId+"&space_id="+String.valueOf(spaceId)+"&name="+fileUrlResource.getFilename();
        JSONObject jsonObject1 = new JSONObject();
        jsonObject1.put("agent_id",thirdAppConfig.getDingtalk().getAgentId());
        jsonObject1.put("code","4604db648103368faed6acac1f1128e1");
        jsonObject1.put("media_id","#iAEHAqRmaWxlA6h5dW5kaXNrMATOITYnCAXNBdsGzQIPB85iMa7HCM0Bxg");
        jsonObject1.put("space_id",String.valueOf(spaceId));
        jsonObject1.put("name",fileUrlResource.getFilename());
        ResponseEntity<JSONObject> request = RestUtil.request(url2, HttpMethod.GET, null, jsonObject1);
        HashMap<String, String> map = new HashMap<>();
        map.put("fileName",fileUrlResource.getFilename());
        map.put("fileSize",String.valueOf(fileSize));
        map.put("fileType",fileUrlResource.getFilename().substring(fileUrlResource.getFilename().lastIndexOf(".")+1));
        map.put("fileId",mediaId);

        map.put("spaceId",String.valueOf(spaceId));
        return map;
    }

    /**
     * 保存文件到自定义或审批钉盘空间
     * @param mediaId
     * @param spaceId
     * @param name 文件名称
     * @return
     */
    @Override
    public String addFileToDingTalk(String mediaId, String spaceId, String name) {
        String accessToken = thirdAppDingtalkService.getAccessToken();
        String url = ThirdAppURLConfig.URL_ADD_FILE.replace("ACCESS_TOKEN",accessToken);

        String s = url + "&agent_id="+thirdAppConfig.getDingtalk().getAgentId()+"&code=" + thirdAppConfig.getDingtalk().getAgentId()+"&media_id"+"&folder_id"+"&space_id"+"&name"+"&overwrite";
        return null;
    }

    /**
     *
     * 钉钉处理消息回调
     * @param msg_signature
     * @param timestamp
     * @param nonce
     * @param json
     */
    @Override
    public Map<String, String> doDingCallBack(String msgSignature, String timestamp, String nonce, JSONObject json) {
        try {
            log.info("=======钉钉处理消息回调请求json==========>{}",json.toJSONString());
            // 1. 从http请求中获取加解密参数
            // 2. 使用加解密类型
            //token     事件订阅里签名token
            //encodingAesKey 好自己随机生成 不使用钉钉生成的，钉钉生成的带数字的会有问题
            // String key = Base64.encodeBase64String(UUID.randomUUID().toString().replaceAll("-","").getBytes());  最后把'='去掉
            // corpid      需要传当前应用的appkey值。
            DingCallbackCrypto callbackCrypto = new DingCallbackCrypto(thirdAppConfig.getDingtalk().getToken(), thirdAppConfig.getDingtalk().getAesKey(), thirdAppConfig.getDingtalk().getAppKey());
            String encryptMsg = json.getString("encrypt");
            String decryptMsg = callbackCrypto.getDecryptMsg(msgSignature, timestamp, nonce, encryptMsg);

            // 3. 反序列化回调事件json数据
            JSONObject eventJson = JSON.parseObject(decryptMsg);
            log.info("===========返回事件json数据=============>{}",eventJson.toJSONString());
            String eventType = eventJson.getString("EventType");
            // todo 根据审批实例ID processInstanceId 查询该审批的状态
            JSONObject oaMsg = this.getOaMsg(eventJson.getString("processInstanceId"));
            // 第一次钉钉设置回调地址 需要返回success   以后将不走该逻辑 只有第一次不存在process_instance属性
            if(ObjectUtil.isEmpty(oaMsg.get("process_instance"))){
                // 5. 返回success的加密数据
                Map<String, String> successMap = callbackCrypto.getEncryptedMap("success");
                return successMap;
            }
            log.info("===========根据审批实例ID processInstanceId 查询该审批的详情json数据=============>{}",oaMsg.toJSONString());
            StringBuilder spRecord = new StringBuilder();
            String spNo=eventJson.getString("processInstanceId");
            Integer spStatus=1;
            LinkedHashMap<String,Object> msg =(LinkedHashMap)oaMsg.get("process_instance");
            //根据审批状态 修改表中合同审批状态
            if("COMPLETED".equals(msg.get("status").toString()) && "agree".equals(msg.get("result"))){
                spStatus=2;
            }
            if("refuse".equals(msg.get("result"))){
                spStatus=3;
            }
            //拼接审批流及状态
            ArrayList<LinkedHashMap> tasks = (ArrayList<LinkedHashMap>) msg.get("tasks");

            for (int i = 0; i < tasks.size(); i++) {
                SysThirdAccount thirdUser = sysThirdAccountService.getOneByThirdUserId(tasks.get(i).get("userid").toString(), ThirdAppConfig.DINGTALK.toLowerCase());
                //或签 传过来的userid 不是真正的thirdappId
                if(ObjectUtil.isNotEmpty(thirdUser)){
                    //根据userid查询真实姓名
                    SysUser user = sysUserService.getById(thirdUser.getSysUserId());
                    spRecord.append(spResultStr(tasks.get(i).get("task_result").toString())).append(ObjectUtil.isEmpty(user) ? thirdUser.getThirdUserId() : user.getRealname());
                    if(i < (tasks.size()-1)){
                        spRecord.append("-->");
                    }
                }
            }

            //hlContractService.changeSpStatus(spNo,spRecord.toString(),spStatus);

            // 5. 返回success的加密数据
            Map<String, String> successMap = callbackCrypto.getEncryptedMap("success");
            return successMap;
        } catch (DingCallbackCrypto.DingTalkEncryptException e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 通过 审批实例ID 获取审批详情
     * @param processInstanceId 审批实例ID
     * @return
     */
    @Override
    public JSONObject getOaMsg(String processInstanceId) {
        //组装请求url
        String accessToken = thirdAppDingtalkService.getAccessToken();
        String url = ThirdAppURLConfig.URL_OA_MSG.replace("ACCESS_TOKEN",accessToken);
        //组装请求提参数 process_instance_id
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("process_instance_id",processInstanceId);
        ResponseEntity<JSONObject> request = RestUtil.request(url,HttpMethod.POST, null, jsonObject);
        return request.getBody();
    }

    private String spResultStr(String result) {
        switch (result) {
            case "AGREE":
                return "[同意]";
            case "REFUSE":
                return "[拒绝]";
            case "REDIRECTED":
                return "[转交]";
            case "NONE":
                return "[审批中]";
            default:
                return "[未知]";
        }
    }

    public static void main(String[] args) {
        JSONObject response = JSON.parseObject("{\"msg\":\"\",\"code\":0,\"data\":{\"instance_code\":\"4E3204B1-61C7-4A1C-BD33-10FC56E0A2C4\"}}");
        String reult = null;
        if (ObjectUtil.isNotEmpty(response.get("code"))&&ObjectUtil.equal(response.get("code"),0)){
            JSONObject asd = JSON.parseObject(String.valueOf(response.get("data")));
            asd.get("instance_code");
            System.out.println(asd.get("instance_code"));
        }
        System.out.println(    "sda");

    }


}

